#!/usr/bin/env python

'''
Sends sniffed IEEE 802.15.4 packets to Wireshark via a named pipe.
(ryan@riverloopsecurity.com)
'''

import sys
import signal
import os, tempfile
import argparse

from killerbee import *

def interrupt(signum, frame):
    global packetcount
    global kb
    global pd
    global pipefname
    global tempdir
    kb.sniffer_off()
    kb.close()
    pd.close()
    os.remove(pipefname)
    os.rmdir(tempdir)
    print("{0} packets captured".format(packetcount))
    sys.exit(0)

pipename = 'zbwireshark'

# Global
packetcount = 0

# Command-line arguments
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('-i', '--iface', '--dev', action='store', dest='devstring')
#parser.add_argument('-g', '--gps', '--ignore', action='append', dest='ignore')
parser.add_argument('-p', '--ppi', action='store_true')
parser.add_argument('-c', '-f', '--channel', action='store', type=int, default=None)
parser.add_argument('-n', '--count', action='store', default=None)
parser.add_argument('-D', action='store_true', dest='showdev')
args = parser.parse_args()

if args.showdev:
    show_dev()
    sys.exit(0)
 
if args.channel == None:
    print >>sys.stderr, "ERROR: Must specify a channel."
    sys.exit(1)

# Make FIFO (named pipe)
tempdir = tempfile.mkdtemp()
pipefname = os.path.join(tempdir, pipename)
try:
    os.mkfifo(pipefname) #default mode 0666 (octal)
except OSError, e:
    print("Failed to create FIFO: {0}".format(e))
    sys.exit(-1)

# Start KillerBee
kb = KillerBee(device=args.devstring)
signal.signal(signal.SIGINT, interrupt)
if not kb.is_valid_channel(args.channel):
    print >>sys.stderr, "ERROR: Must specify a valid IEEE 802.15.4 channel for the selected device."
    kb.close()
    sys.exit(1)
kb.set_channel(args.channel)
kb.sniffer_on()

# Start wireshark as soon as KillerBee succeeds
try:
    rc = os.fork()
    if rc == 0:
        os.execlp("wireshark", "/usr/bin/wireshark", "-k", "-i", pipefname)
except OSError, e:
    print("Failed to automatically spawn wireshark: {0}".format(e))
    print("You should manually point Wireshark to read from the pipe file: {0}".format(pipefname))

pd = PcapDumper(DLT_IEEE802_15_4, pipefname, ppi=args.ppi)
rf_freq_mhz = (args.channel - 10) * 5 + 2400
print("zbwireshark: listening on \'{0}\', sending to \'{1}\'".format(kb.get_dev_info()[0], pipefname))

try:
    while args.count != packetcount:
        packet = kb.pnext()
        if packet != None:
            packetcount+=1
            pd.pcap_dump(packet['bytes'], ant_dbm=packet['dbm'], freq_mhz=rf_freq_mhz)
except KeyboardInterrupt:
    pass
except IOError as e:
    if e.errno == 32:
        print("ERROR: Pipe broken. Was Wireshark closed or stopped?")

interrupt(0, 0) #shutdown and exit

